const crypto = require("crypto");

const UNUSABLE_PASSWORD = "!";
/**
 * getHexDigest 加密字符串
 * @param {string} algorithm 加密算法
 * @param {string} salt 随机字符串
 * @param {string} raw 明文
 * @returns 密文
 */
function getHexDigest(algorithm, salt, raw) {
  let hash = crypto.createHash(algorithm);
  hash.update(salt + raw);
  return hash.digest("hex");
}

/**
 * makePassword 密码加密函数
 * @param {string} rawPassword 明文密码
 * @returns 加密后的密文
 */
function makePassword(rawPassword) {
  if (rawPassword == undefined) return UNUSABLE_PASSWORD;
  let algo = "sha1",
    rand = () => Math.random().toString(16).slice(-8),
    salt = getHexDigest(algo, rand(), rand()).slice(-8),
    hsh = getHexDigest(algo, salt, rawPassword);
  return `${algo}$${salt}$${hsh}`;
}

/**
 * checkPassword 验证密码
 * @param {string} rawPassword 明文密码
 * @param {string} encPassword 密文
 */
function checkPassword(rawPassword, encPassword) {
  let [algo, salt, hsh] = encPassword.split("$");
  return hsh == getHexDigest(algo, salt, rawPassword);
}

const emptyFn = () => {};
const isObject = (o) => o !== null && typeof o === "object";
/**
 * isEmpty 判断对象是否为空
 * @param {any} v any object
 * @returns {boolean}
 */
const isEmpty = (v) => {
  if (v === null || v === undefined || v === "") return true;
  if (Array.isArray(v) && v.length == 0) return true;
  if (isObject(v) && Object.keys(v).length == 0) return true;
  return false;
};
/**
 * not 高阶函数：对参数执行结果取反
 * @param {function} fn 任何返回布尔类型的函数
 * @returns {function}
 */
const not = (fn) => (...args) => !fn(...args);
/**
 * notEmpty 与isEmpty相反
 * @param {any} v any object
 * @returns {boolean}
 */
const notEmpty = not(isEmpty);

const stringify = (obj) => {
  let items = [];
  for (let key in obj) {
    items.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
  }
  return items.join("&");
};

module.exports = {
  emptyFn,
  isObject,
  isEmpty,
  not,
  notEmpty,
  stringify,
  getHexDigest,
  makePassword,
  checkPassword,
};
